﻿using System.Drawing;
using System.Drawing.Imaging;
using JNPF.Common.Const;
using JNPF.Common.Core.Manager;
using JNPF.Common.Extension;
using JNPF.DependencyInjection;

namespace JNPF.Common.Core.Captcha.General;

/// <summary>
/// 常规验证码.
/// </summary>
public class GeneralCaptcha : IGeneralCaptcha, ITransient
{
    private readonly ICacheManager _cacheManager;

    /// <summary>
    /// 构造函数.
    /// </summary>
    /// <param name="cacheManager"></param>
    public GeneralCaptcha(ICacheManager cacheManager)
    {
        _cacheManager = cacheManager;
    }

    /// <summary>
    /// 常规验证码.
    /// </summary>
    /// <param name="timestamp">时间戳.</param>
    /// <param name="width">宽度.</param>
    /// <param name="height">高度.</param>
    /// <param name="length">长度.</param>
    /// <returns></returns>
    public async Task<byte[]> CreateCaptchaImage(string timestamp, int width, int height, int length = 4)
    {
        return await Draw(timestamp, width, height, length);
    }

    /// <summary>
    /// 画.
    /// </summary>
    /// <param name="timestamp">时间抽.</param>
    /// <param name="width">宽度.</param>
    /// <param name="height">高度.</param>
    /// <param name="length">长度.</param>
    /// <returns></returns>
    private async Task<byte[]> Draw(string timestamp, int width, int height, int length = 4)
    {
        int fontSize = 16;

        // 颜色列表，用于验证码、噪线、噪点
        Color[] color = { Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.Brown, Color.DarkBlue };

        // 字体列表，用于验证码
        string[] fonts = new[] { "Times New Roman", "Verdana", "Arial", "Gungsuh", "Impact" };

        // 验证码随机数
        Random codeRandom = new Random();
        string code = codeRandom.NextLetterAndNumberString(length); // 随机字符串集合

        using (Bitmap bmp = new Bitmap(width, height))
        using (Graphics g = Graphics.FromImage(bmp))
        using (MemoryStream ms = new MemoryStream())
        {
            g.Clear(Color.White);
            Random rnd = new Random();

            // 画噪线
            for (int i = 0; i < 1; i++)
            {
                int x1 = rnd.Next(width);
                int y1 = rnd.Next(height);
                int x2 = rnd.Next(width);
                int y2 = rnd.Next(height);
                var clr = color[rnd.Next(color.Length)];
                g.DrawLine(new Pen(clr), x1, y1, x2, y2);
            }

            // 画验证码字符串
            string fnt;
            Font ft;
            for (int i = 0; i < code.Length; i++)
            {
                fnt = fonts[rnd.Next(fonts.Length)];
                ft = new Font(fnt, fontSize);
                var clr = color[rnd.Next(color.Length)];
                g.DrawString(code[i].ToString(), ft, new SolidBrush(clr), ((float)i * 24) + 2, 0);
            }

            // 缓存验证码正确集合
            await SetCode(timestamp, code, TimeSpan.FromMinutes(5));

            // 将验证码图片写入内存流
            bmp.Save(ms, ImageFormat.Jpeg);
            return ms.ToArray();
        }
    }

    /// <summary>
    /// 保存验证码缓存.
    /// </summary>
    /// <param name="timestamp">时间戳.</param>
    /// <param name="code">验证码.</param>
    /// <param name="timeSpan">过期时间.</param>
    public async Task<bool> SetCode(string timestamp, string code, TimeSpan timeSpan)
    {
        string cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYCODE, timestamp);
        return await _cacheManager.SetAsync(cacheKey, code, timeSpan);
    }
}